package com.dataManager.www.controller;

import com.dataManager.www.entity.User;
import com.dataManager.www.service.FileService;
import com.dataManager.www.service.UserService;
import com.dataManager.www.utils.FileUtils;
import com.dataManager.www.utils.SystemCode;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import sun.misc.BASE64Encoder;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Controller
@RequestMapping(value = "/sys/file")
public class FileController {

    private static final int BUFFER_SIZE = 100 * 1024;
    private static final Logger logger = Logger.getLogger(FileController.class);
    @Autowired
    private FileService fileService;

    @Autowired
    private UserService userService;

    /**
     * 上传文件接收类（暂时弃用）
     * @param file
     * @return
     */
    @RequestMapping(value = "upload")
    @ResponseBody
    public String fileUpload(@RequestParam("file") MultipartFile file) {
        System.out.println("fileUpload");
        if (!file.isEmpty()) {
            try {
                // 文件存放服务端的位置
                String rootPath = "d:/tmp";
                File dir = new File(rootPath + File.separator + "tmpFiles");
                if (!dir.exists())
                    dir.mkdirs();
                // 写文件到服务器
                File serverFile = new File(dir.getAbsolutePath() + File.separator + file.getOriginalFilename());
                file.transferTo(serverFile);
                return "成功上传文件至=" +  file.getOriginalFilename();
            } catch (Exception e) {
                return "未能成功上传" +  file.getOriginalFilename() + " => " + e.getMessage();
            }
        } else {
            return "上传文件 " +  file.getOriginalFilename() + " 失败，因为文件为空";
        }
    }

    /**
     * 接收上传文件并存放到指定目录
     * @param file
     * @param request
     * @return
     */
    @ResponseBody
    @RequestMapping(value="plupload",method= RequestMethod.POST)
    public String plupload(@RequestParam MultipartFile file, HttpServletRequest request) {
        User user = (User) request.getSession().getAttribute("user");
        double alreadyUse = fileService.calculateFileSizeByUserId(user.getId());
        System.out.println("该用户已使用容量："+alreadyUse+"MB");
        double haveDiskSize = userService.sumTotalDiskSizeByUser(user);
        System.out.println("该用户共有："+haveDiskSize+"MB");
        double fileSize = file.getSize()*1.0/1024/1024;
        System.out.println("文件大小："+fileSize+"MB");
        if(alreadyUse+fileSize>haveDiskSize){
            return SystemCode.FULL_DISK_SIZE;
        }

        try {
            String name = request.getParameter("name");
            Integer chunk = 0, chunks = 0;
            if(null != request.getParameter("chunk") && !request.getParameter("chunk").equals("")){
                chunk = Integer.valueOf(request.getParameter("chunk"));
            }
            if(null != request.getParameter("chunks") && !request.getParameter("chunks").equals("")){
                chunks = Integer.valueOf(request.getParameter("chunks"));
            }
            logger.info("chunk:[" + chunk + "] chunks:[" + chunks + "]");
            File folder = new File("d:/tmp");
            if (!folder.exists()) {
                folder.mkdirs();
            }

            //目标文件
            File destFile = new File(folder, name);
            //文件已存在删除旧文件（上传了同名的文件）
            if (chunk == 0 && destFile.exists()) {
                destFile.delete();
                destFile = new File(folder, name);
            }
            //合成文件
            appendFile(file.getInputStream(), destFile);
            if (chunk == chunks - 1) {
                logger.info("上传完成");
            }else {
                logger.info("还剩["+(chunks-1-chunk)+"]个块文件");
            }

        } catch (IOException e) {
            logger.error(e.getMessage());
        }

        return "";
    }

    private void appendFile(InputStream in, File destFile) {
        OutputStream out = null;
        try {
            // plupload 配置了chunk的时候新上传的文件append到文件末尾
            if (destFile.exists()) {
                out = new BufferedOutputStream(new FileOutputStream(destFile, true), BUFFER_SIZE);
            } else {
                out = new BufferedOutputStream(new FileOutputStream(destFile),BUFFER_SIZE);
            }
            in = new BufferedInputStream(in, BUFFER_SIZE);

            int len = 0;
            byte[] buffer = new byte[BUFFER_SIZE];
            while ((len = in.read(buffer)) > 0) {
                out.write(buffer, 0, len);
            }
        } catch (Exception e) {
            logger.error(e.getMessage());
        } finally {
            try {
                if (null != in) {
                    in.close();
                }
                if(null != out){
                    out.close();
                }
            } catch (IOException e) {
                logger.error(e.getMessage());
            }
        }
    }


    /**
     * 上传文件后将文件相关信息保存到数据库
     * @param file
     * @param request
     * @return
     * @throws InterruptedException
     */
    @ResponseBody
    @RequestMapping(value="addUploadInfo",method= RequestMethod.POST)
    public String addUploadInfo(@RequestBody com.dataManager.www.entity.File file, HttpServletRequest request) throws InterruptedException {
        User user = (User) request.getSession().getAttribute("user");

        FileUtils.fileMove("d:/tmp","d:/uploadData/"+file.getFileName());
        long byteFileSize = FileUtils.getFileSize("d:/uploadData/"+file.getFileName());
        file.setFileSize(byteFileSize/1024/1024);
        System.out.println(file.getFileSize());
        file.setFilePath("d:/uploadData/"+file.getFileName());
        String labels = file.getLabels();
        file.setLabels(labels.replace("ဆ",","));
        file.setFileType("文件组");
        file.setFileVersion(1);
        file.setDownloadCount(0);
        file.setWatchCount(0);
        file.setCreateDate(new Date());
        file.setUserId(user.getId());
        fileService.add(file);
        return SystemCode.SUCCESS;
    }


    /**
     * 列出所有文件（AJAX）
     * @return
     */
    @RequestMapping(value = "listFile")
    @ResponseBody
    public Map<String, Object> listFile(@RequestParam(value = "fileName",required = false) String fileName,
                                        @RequestParam(value = "fileType",required = false) String fileType,
                                        @RequestParam(value = "labels",required = false) String labels,
                                        HttpServletRequest request){
        User user = (User) request.getSession().getAttribute("user");
        com.dataManager.www.entity.File file = new com.dataManager.www.entity.File();
        file.setFileName(fileName);
        file.setFileType(fileType);
        file.setLabels(labels);
        file.setUserId(user.getId());
        List<com.dataManager.www.entity.File> userList = fileService.listByObject(file);
        Map<String, Object> tableJson = new HashMap<String, Object>();
        tableJson.put("code",0);
        tableJson.put("msg","");
        tableJson.put("count",userList.size());
        tableJson.put("data",userList);
        return tableJson;
    }

    @RequestMapping(value="download",method=RequestMethod.POST)
    public void download(@RequestParam(value = "id",required = false) String id,HttpServletRequest request,HttpServletResponse response) throws IOException {
        System.out.println("下载");
        Map para = new HashMap();
        para.put("id",id);
        com.dataManager.www.entity.File downLoadFiles = fileService.get(para);
        String filename = downLoadFiles.getFileName();
        System.out.println("下载文件名："+filename);
        System.out.println("下载路径："+downLoadFiles.getFilePath());
        filename = FileUtils.zipFiles(downLoadFiles.getFilePath(),filename);
        /*******************1.接收请求参数***********************************/
        //获取文件名,接收文件名参数

        /*******************2.对接收的参数进行编码处理**************************/
        /**因为使用的是UTF-8的编码形式，所以不需要进行转码**/
        //获取参数  ，默认会对参数进行编码    ISO8859-1
        //把乱码转回二进制位
//		byte[] bytes = name.getBytes("ISO8859-1");
        //再去使用UTF-8进行编码
//		name = new String(name.getBytes(),"UTF-8");

        /*******************3.告诉浏览器响应的文件的类型*************************/
        // 根据文件名来获取mime类型
        String mimeType = request.getSession().getServletContext().getMimeType(filename);
        // 设置 mimeType
        response.setContentType(mimeType);

        /*******************4.告诉浏览器以附件的形式下载*************************/
        // 获取客户端信息
        String agent = request.getHeader("User-Agent");
        // 定义一个变量记录编码之后的名字
        String filenameEncoder = "";
        if (agent.contains("MSIE")) {
            // IE编码
            filenameEncoder = URLEncoder.encode(filename, "utf-8");
            filenameEncoder = filenameEncoder.replace("+", " ");
        } else if (agent.contains("Firefox")) {
            // 火狐编码
            BASE64Encoder base64Encoder = new BASE64Encoder();
            filenameEncoder = "=?utf-8?B?" + base64Encoder.encode(filename.getBytes("utf-8")) + "?=";
        } else {
            // 浏览器编码
            filenameEncoder = URLEncoder.encode(filename, "utf-8");
        }
        // 告诉浏览器是以附件形式来下载 不要解析
        response.setHeader("Content-Disposition", "attachment;filename=" + filenameEncoder);

        /*******************5.输出对应的流*************************/
        //获取文件的绝对路径,拼接文件的路径
        String path = filename;

        System.out.println("下载文件的路径" + path);
        //写入流中
        FileInputStream is = new FileInputStream(path);
        //获取相应的输出流
        ServletOutputStream os = response.getOutputStream();
        byte[] b = new byte[1024];
        int len;
        //写入浏览器中
        while((len = is.read(b)) != -1){
            os.write(b, 0, len);
        }
        //关闭对应的流
        os.close();
        is.close();
    }

}
